package cn.edu.xmu.orderpayment.order.service;

import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;

import cn.edu.xmu.orderpayment.order.constant.Constants;
import cn.edu.xmu.orderpayment.order.dao.OrderDao;
import cn.edu.xmu.orderpayment.order.microservice.*;
import cn.edu.xmu.orderpayment.order.microservice.PaymentService;
import cn.edu.xmu.orderpayment.order.microservice.vo.*;
import cn.edu.xmu.orderpayment.order.model.bo.Order;
import cn.edu.xmu.orderpayment.order.model.bo.OrderItem;
import cn.edu.xmu.orderpayment.order.model.enums.ActState;
import cn.edu.xmu.orderpayment.order.model.enums.DocumentType;
import cn.edu.xmu.orderpayment.order.model.po.OrderItemPo;
import cn.edu.xmu.orderpayment.order.model.po.OrderPo;
import cn.edu.xmu.orderpayment.order.model.vo.*;
import cn.edu.xmu.orderpayment.order.mq.RocketMQService;
import cn.edu.xmu.privilegegateway.annotation.util.InternalReturnObject;
import org.aspectj.weaver.ast.Or;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.edu.xmu.oomall.core.util.Common.getListRetVo;
import static cn.edu.xmu.oomall.core.util.ReturnNo.RESOURCE_ID_NOTEXIST;
import static cn.edu.xmu.oomall.core.util.ReturnNo.RESOURCE_ID_OUTSCOPE;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.setPoModifiedFields;
import static cn.edu.xmu.oomall.core.util.ReturnNo.*;
import static cn.edu.xmu.oomall.core.util.ReturnNo.GOODS_STOCK_SHORTAGE;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.*;

/**
 *
 * @author Chencheng Liao 22920192204238
 * @Date 2021/12/11
 */
@Service
public class CustomerOrderService {

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private CouponService couponService;

    @Autowired
    private FreightService freightService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private ShopService shopService;

    @Autowired
    private RocketMQService rocketMQService;



    /**
     * 获得订单所有状态
     *
     * @param
     * @return Object
     * @author Chencheng Liao 22920192204238
     * @Date 2021/12/11
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject getOrderStates() {
        return orderDao.getOrderState();
    }

    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject<Order> getOrderByOrderId(Long OrderId) {
        return orderDao.getOrderById(OrderId);
    }

    /**
     * 买家查看查询名下的订单(概要)
     * @param loginUser 用户ID
     * @param orderSn 订单编号
     * @param state 订单状态
     * @param beginTime 订单开始时间
     * @param endTime 订单结束时间
     * @param page 页码
     * @param pageSize 页规格
     * @return object
     * @author Chencheng Liao 22920192204238
     * @Date 2021/12/13
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject customerGetAllSimpleOrders(Long loginUser, String orderSn, Integer state,
                                                   ZonedDateTime beginTime, ZonedDateTime endTime,
                                                   Integer page, Integer pageSize) {

        return orderDao.customerGetAllSimpleOrders(loginUser,orderSn,state,beginTime,endTime,page,pageSize);
    }

    /**
     * 买家查询单个订单
     *
     * @param loginUserId 用户id
     * @param id 订单id
     * @return object
     * @author Chencheng Liao 22920192204238
     * @Date 2021/12/14
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public ReturnObject customerGetAllOrders(Long loginUserId, Long id) {
        ReturnObject returnObject = orderDao.getOrder(id);
        if (returnObject.getData() == null) return returnObject;
        Order order = (Order) returnObject.getData();
        if (order.getBeDeleted().equals(Byte.valueOf("1"))) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该id订单不存在");
        }

        if (!order.getCustomerId().equals(loginUserId)) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于此用户");
        }

        InternalReturnObject customerRetObj = customerService.getCustomerById(order.getCustomerId());
        SimpleCustomerRetVo simpleCustomerRetVo = (SimpleCustomerRetVo) customerRetObj.getData();
        if (simpleCustomerRetVo == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该用户不存在");
        }

        ShopSimpleRetVo shopRetVo = new ShopSimpleRetVo(0L, null);
        if (order.getShopId() != 0) {
            InternalReturnObject shopRetObj = shopService.getShopById(order.getShopId());
            shopRetVo = (ShopSimpleRetVo) shopRetObj.getData();
        }

        ReturnObject<List> orderItemsRetObj = orderDao.getOrderItemsByOrderId(id);
        List<SimpleOrderItemRetVo> list = new ArrayList<>();
        if (!(orderItemsRetObj.getData() == null || orderItemsRetObj.getData().size() == 0)) {
            list.addAll((List<SimpleOrderItemRetVo>) getListRetVo(orderItemsRetObj, SimpleOrderItemRetVo.class).getData());
        }

        OrderInfoRetVo orderInfoRetVo = cloneVo(order, OrderInfoRetVo.class);
        orderInfoRetVo.setCustomer(simpleCustomerRetVo);
        orderInfoRetVo.setShop(shopRetVo);
        orderInfoRetVo.setOrderItem(list);

        return new ReturnObject(orderInfoRetVo);
    }

    /**
     * 查询自己订单的支付信息
     *
     * @param userId 用户id
     * @param id 订单id
     * @return object
     * @author Chencheng Liao 22920192204238
     * @Date 2021/12/22
     */
    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getOrderPayInfo(Long id, Long userId) {
        ReturnObject<Order> ret = orderDao.getOrder(id);
        if (ret.getData() == null) return new ReturnObject(RESOURCE_ID_NOTEXIST, "该订单不存在");
        Order order = ret.getData();
        if (!Objects.equals(order.getCustomerId(), userId)) return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于该用户");
        String orderSn = order.getOrderSn();
        if (order.getState().equals(Order.State.PENDING_FINAL_PAYMENT.getCode())) {
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject = paymentService.getPaymentByDocumentId(orderSn + "-D");
            if (paymentRetVoInternalReturnObject.getData() == null
                    || paymentRetVoInternalReturnObject.getData().size() == 0)
                return new ReturnObject<>(RESOURCE_ID_NOTEXIST, "没有支付单");
            return new ReturnObject(paymentRetVoInternalReturnObject.getData());
        }
        else if(order.getAdvancesaleId()!=null&&!order.getAdvancesaleId().equals(0L)){
            List<PaymentRetVo> paymentRetVoList=new ArrayList<>();
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject=paymentService.getPaymentByDocumentId(orderSn+"-D");
            if(paymentRetVoInternalReturnObject.getData()==null)return new ReturnObject<>(RESOURCE_ID_NOTEXIST,"没有支付单");
            paymentRetVoList.addAll(paymentRetVoInternalReturnObject.getData());
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject1 = paymentService.getPaymentByDocumentId(orderSn + "-W");
            if (paymentRetVoInternalReturnObject1.getData() == null)
                return new ReturnObject<>(RESOURCE_ID_NOTEXIST, "没有支付单");
            paymentRetVoList.addAll(paymentRetVoInternalReturnObject.getData());
            return new ReturnObject(paymentRetVoList);
        } else {
            InternalReturnObject<List<PaymentRetVo>> paymentRetVoInternalReturnObject = paymentService.getPaymentByDocumentId(orderSn);
            if (paymentRetVoInternalReturnObject.getData() == null)
                return new ReturnObject(RESOURCE_ID_NOTEXIST, "该支付单不存在");
            return new ReturnObject(paymentRetVoInternalReturnObject.getData());
        }
    }

    /**
     * 查询自己订单的退款信息
     *
     * @param userId 用户id
     * @param id 订单id
     * @return object
     * @author Chencheng Liao 22920192204238
     * @Date 2021/12/22
     */
    @Transactional(rollbackFor = Exception.class, readOnly = true)
    public ReturnObject getOrderRefundInfo(Long id, Long userId) {
        ReturnObject<Order> res = orderDao.getOrder(id);
        if (res.getData() == null) return res;
        Order order = res.getData();
        if (!Objects.equals(order.getCustomerId(), userId)) return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于该用户");
        String documentId = order.getOrderSn();
        InternalReturnObject<List<RefundRetVo>> paymentRetVoInternalReturnObject = paymentService.getRefundByDocumentId(documentId);
        if (paymentRetVoInternalReturnObject.getData() == null)
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "该退款单不存在");
        return new ReturnObject(paymentRetVoInternalReturnObject.getData());
    }



    /**
    * @Description: 修改订单
    * @Param: [id, updateOrderVo, loginUser, loginUserName]
    * @return: ReturnObject
    * @Author: Li Yixuan 22920192204232
    * @Date: 2021/12/13
    * @Modify: 2021/12/24
    */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject updateOrder(Long id, Order orderBo, Long loginUser, String loginUserName) {
        //根据订单id获得订单
        ReturnObject ret = orderDao.getOrder(id);
        if (ret.getCode().equals(RESOURCE_ID_NOTEXIST)) {
            return ret;
        }
        Order order = (Order) ret.getData();

        if (!order.getRegionId().equals(orderBo.getRegionId())) {
            return new ReturnObject(ReturnNo.STATENOTALLOW, "订单地址费用变化");
        }
        if (!loginUser.equals(order.getCustomerId())) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE, "不能修改其他用户的订单");
        }
        // 判断order是否未发货
        Integer orderState = order.getState();
        if (orderState.equals(Order.State.SHIPPED.getCode()) || orderState.equals(Order.State.CANCELED.getCode())
                || orderState.equals(Order.State.COMPLETED.getCode()) || order.getState().equals(Order.State.HAS_REFUNDED.getCode())
                || order.getState().equals(Order.State.WAIT_REFUND.getCode())) {
            return new ReturnObject(ReturnNo.STATENOTALLOW, "当前状态禁止此操作");
        }
        //分单判断
        try{
            List<Order> orders=new ArrayList<>();
            //如果是父订单
            if(order.getPid()==0){
                orders = (List<Order>) getCanBeUpdatedSubOrdersByPid(order.getId(),loginUser).getData();
                //如果有子订单
                if(orders.size()!=0){
                    for (Order o:orders)
                    {
                        orderBo.setId(o.getId());
                        ret=orderDao.updateOrder(orderBo, loginUser, loginUserName);
                        if(ret.getData()==ReturnNo.INTERNAL_SERVER_ERR)
                            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
                    }
                }
                //改自己
                orderBo.setId(id);
                ret=orderDao.updateOrder(orderBo, loginUser, loginUserName);
                if(ret.getData()==ReturnNo.INTERNAL_SERVER_ERR)
                    return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
            }else{
                orders = (List<Order>) getCanBeUpdatedSubOrdersByPid(order.getPid(),loginUser).getData();
                //如果有子订单
                if(orders.size()!=0){
                    for (Order o:orders)
                    {
                        orderBo.setId(o.getId());
                        ret=orderDao.updateOrder(orderBo, loginUser, loginUserName);
                        if(ret.getData()==ReturnNo.INTERNAL_SERVER_ERR)
                            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
                    }
                }
                //改父订单
                orderBo.setId(order.getPid());
                ret=orderDao.updateOrder(orderBo, loginUser, loginUserName);
                if(ret.getData()==ReturnNo.INTERNAL_SERVER_ERR)
                    return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR);
                }
            }
            catch (Exception e)  {
                return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST);
            }
        return new ReturnObject();
    }

    /**
     * @Description: 买家逻辑删除本人名下订单
     * @Param: [id, loginUser, loginUserName]
     * @return: cn.edu.xmu.oomall.core.util.ReturnObject
     * @Author: Li Yixuan 22920192204232
     * @Date: 2021/12/16
     * @Modify: 2021/12/24
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject deleteOrder(Long id, Long loginUser, String loginUserName) {
        Order order;
        ReturnObject ret;
        try {
            order = orderDao.getOrderById(id).getData();
        }
        catch (Exception e) {
            return new ReturnObject<>(ReturnNo.RESOURCE_ID_NOTEXIST);
        }
        setPoModifiedFields(order, loginUser, loginUserName);
        if (!loginUser.equals(order.getCustomerId())) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE,"不是顾客订单");
        }
        if (!(order.getState().equals(Order.State.COMPLETED.getCode()) || order.getState().equals(Order.State.CANCELED.getCode()))) {
            return new ReturnObject(ReturnNo.STATENOTALLOW, "当前状态禁止此操作");
        }
        return orderDao.cutomerDeleteOrder(id);
    }


    /**
     * @Author: Li Yixuan 22920192204232
     * @Date: 2021/12/19
     */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject cancelOrder(Long id, Long loginUser, String loginUserName) {
        //看看是不是本用户的订单
        ReturnObject returnObject = orderDao.getOrder(id);
        if (returnObject.getData() == null) return returnObject;
        Order order = (Order) returnObject.getData();
        if (!Objects.equals(loginUser, order.getCustomerId())) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该订单不属于该用户");
        }
        return internalCancelOrder(loginUser, loginUserName, order);
    }


    /**
    * @Description: 买家标记确认收货
    * @Param: [id, loginUser, loginUserName]
    * @return: ReturnObject
    * @Author: Li Yixuan 22920192204232
    * @Date: 2021/12/16
    * @Modify: 2021/12/24
    */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject customerConfirmOrder(Long id, Long loginUser, String loginUserName) {
        Order order;
        try {
            order = orderDao.getOrderById(id).getData();
        }
        catch (Exception e) {
            return new ReturnObject<>(ReturnNo.RESOURCE_ID_NOTEXIST,"此订单不存在");
        }
        if (!loginUser.equals(order.getCustomerId())) {
            return new ReturnObject(ReturnNo.RESOURCE_ID_OUTSCOPE,"不是该顾客订单");
        }
        if (!order.getState().equals(Order.State.SHIPPED.getCode())) {
            return new ReturnObject(ReturnNo.STATENOTALLOW, "当前状态禁止此操作");
        }
        setPoModifiedFields(order, loginUser, loginUserName);
        ReturnObject ret;
        //分单判断
        try{
            List<Order> orders=new ArrayList<>();
            //如果是父订单
            if(order.getPid()==0){
                orders = (List<Order>) getCanBeConfirmSubOrdersByPid(order.getId(),loginUser).getData();
                //如果有子订单
                if(orders.size()!=0){
                    for (Order o:orders)
                    {
                        o.setState(Order.State.COMPLETED.getCode());
                        ret = orderDao.updateOrderState(o);
                        if(ret.getCode()!= ReturnNo.OK)
                            return ret;
                    }
                }
                //改自己
                order.setState(Order.State.COMPLETED.getCode());
                ret = orderDao.updateOrderState(order);
                if(ret.getCode()!= ReturnNo.OK)
                    return ret;
            }else{
                orders = (List<Order>) getCanBeConfirmSubOrdersByPid(order.getPid(),loginUser).getData();
                //如果有子订单
                if(orders.size()!=0){
                    for (Order o:orders)
                    {
                        o.setState(Order.State.COMPLETED.getCode());
                        ret = orderDao.updateOrderState(o);
                        if(ret.getCode()!= ReturnNo.OK)
                            return ret;
                    }
                }
                //改父订单
                Order porder= orderDao.getOrderById(order.getPid()).getData();
                porder.setState(Order.State.COMPLETED.getCode());
                ret = orderDao.updateOrderState(porder);
                if(ret.getCode()!= ReturnNo.OK)
                    return ret;
            }
        }
        catch (Exception e)  {
            return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST);
        }
        return new ReturnObject();
    }

    @Transactional(rollbackFor = Exception.class)
    public ReturnObject getCanBeUpdatedSubOrdersByPid(Long pid,Long loginUser)
    {
        List<Integer> stateList=new ArrayList<>();
        stateList.add(Order.State.NEW_ORDER.getCode());
        stateList.add(Order.State.PENDING_FINAL_PAYMENT.getCode());
        stateList.add(Order.State.PENDING_DELIVERY.getCode());
        stateList.add(Order.State.PAYMENT_COMPLETED.getCode());
        stateList.add(Order.State.PENDING_PAYMENT.getCode());
        stateList.add(Order.State.PENDING_GROUPING.getCode());
        return orderDao.getSubOrdersByPid(pid,loginUser,stateList);
    }

    @Transactional(rollbackFor = Exception.class)
    public ReturnObject getCanBeConfirmSubOrdersByPid(Long pid,Long loginUser)
    {
        List<Integer> stateList=new ArrayList<>();
        stateList.add(Order.State.SHIPPED.getCode());
        return orderDao.getSubOrdersByPid(pid,loginUser,stateList);
    }

    /**
    * @Description: 买家申请建立订单
    * @Param: order
    * @return:  ReturnObject
    * @Author: Li Yixuan 22920192204232
    * @Date: 2021/12/18
    * @Modify: 2021/12/18
    */
    @Transactional(rollbackFor = Exception.class)
    public ReturnObject createMyselfOrder(NewOrderVo vo, Long userId, String userName) {


        SimpleRegionRetVo regionRetVo = freightService.getRegionById(vo.getRegionId()).getData();
        if (regionRetVo == null) {
            return new ReturnObject(RESOURCE_ID_NOTEXIST, "地区不存在");
        }
        if (regionRetVo.getState() == (byte)1) {
            return new ReturnObject(FREIGHT_REGION_NOTREACH, "该地区停发");
        }
        if (regionRetVo.getState() == (byte)2) {
            return new ReturnObject(FREIGHT_REGIONOBSOLETE, "该地区已废弃");
        }
        if (vo.getAdvanceSaleId() != null && vo.getGrouponId() != null) {
            return new ReturnObject(ACTIVITY_NOTFOUND, "无法同时参与团购和预售");
        }
        if (vo.getAdvanceSaleId() != null) {
            InternalReturnObject<AdvanceSaleRetVo> actRet = activityService.getAdvanceActById(vo.getAdvanceSaleId());
            if (actRet == null || actRet.getData() == null) {
                return new ReturnObject(RESOURCE_ID_NOTEXIST, "预售活动不存在");
            }
            if (actRet.getData().getBeginTime().isAfter(ZonedDateTime.now())) {
                return new ReturnObject(STATENOTALLOW, "预售活动未开始");
            }
            List<OrderItemVo> itemVoList = vo.getOrderItems();
            if (itemVoList.size() > 1) return new ReturnObject<>(GOODS_STOCK_SHORTAGE, "预售活动只允许下单一个商品");
            return internalCreateOrder(vo, userId, userName, actRet.getData(), null);
        } else if (vo.getGrouponId() != null) {
            InternalReturnObject<GrouponActRetVo> actRet = activityService.getGrouponActById(vo.getGrouponId());
            if (actRet == null || actRet.getData() == null) {
                return new ReturnObject(RESOURCE_ID_NOTEXIST, "团购活动不存在");
            }
            if (actRet.getData().getState() != ActState.ONLINE) return new ReturnObject<>(STATENOTALLOW, "团购活动没有上线");
            List<OrderItemVo> itemVoList = vo.getOrderItems();
            if (itemVoList.size() > 1) return new ReturnObject<>(GOODS_STOCK_SHORTAGE, "团购活动只允许下单一个商品");
            return internalCreateOrder(vo, userId, userName, null, actRet.getData());
        } else {
            return internalCreateOrder(vo, userId, userName, null, null);
        }
    }

    private ReturnObject internalCreateOrder(NewOrderVo vo, Long userId, String userName, AdvanceSaleRetVo advanceActRetVo, GrouponActRetVo grouponActRetVo) {

        List<OrderItemVo> itemVoList = vo.getOrderItems();

        List<ProductRetVo> productRetVoList = new ArrayList<>();
        List<OnSaleRetVo> onSaleRetVoList = new ArrayList<>();
        List<OrderItem> orderItemList = new ArrayList<>();
        // 优惠券set 可能几个item用同一个coupon
        Set<Long> couponSet = new HashSet<>();
        // 算优惠和运费列表
        List<FreightCalculatingPostVo> freightCalVoList = new ArrayList<>();
        List<CouponCalVo> couponCalVoList = new ArrayList<>();

        Long allPrice = 0L;
        for (OrderItemVo itemVo : itemVoList) {
            InternalReturnObject<ProductRetVo> productRet = goodsService.getProductById(itemVo.getProductId());
            InternalReturnObject<OnSaleRetVo> onSaleRet = goodsService.selectFullOnsale(itemVo.getOnsaleId());
            // check product and onsale valid
            ReturnObject errorReturn = checkProductOnSale(productRet, onSaleRet);
            if (errorReturn.getCode() != OK) return errorReturn;
            if (itemVo.getCouponId() != null) {
                // check couponAct valid
                ReturnObject couponErrorReturn = (ReturnObject) customerService.isCouponExists(itemVo.getCouponId(),userId);
                if (couponErrorReturn.getCode() != OK) return couponErrorReturn;
            }
            productRetVoList.add(productRet.getData());
            onSaleRetVoList.add(onSaleRet.getData());

            // 优惠计算列表加入
            CouponCalVo couponCalVo = new CouponCalVo(itemVo.getProductId(), itemVo.getOnsaleId(), itemVo.getQuantity(), onSaleRet.getData().getPrice(), itemVo.getCouponActivityId());
            couponCalVoList.add(couponCalVo);

            // 运费计算列表加入
            FreightCalculatingPostVo freightCalVo = new FreightCalculatingPostVo(productRet.getData(), itemVo.getQuantity());
            freightCalVoList.add(freightCalVo);

            // OrderItem列表加入
            OrderItem orderItem = cloneVo(itemVo, OrderItem.class);
            orderItem.init();
            orderItem.setShopId(productRet.getData().getShop().getId());
            orderItem.setPrice(onSaleRet.getData().getPrice());
            orderItem.setName(productRet.getData().getName());
            setPoCreatedFields(orderItem, userId, userName);
            orderItemList.add(orderItem);

            // 算出总金额
            allPrice += orderItem.getPrice() * orderItem.getQuantity();

            // 优惠券set加入
            if (orderItem.getCouponId() != null) couponSet.add(orderItem.getCouponId());

        }

        // 预扣库存
        for (int i = 0; i < itemVoList.size(); i++) {
            OrderItemVo itemVo = itemVoList.get(i);
            SimpleShopVo shop = goodsService.selectFullOnsale(itemVo.getOnsaleId()).getData().getShop();
            goodsService.decreaseOnSale(shop.getId(), itemVo.getOnsaleId(), new QuantityVo(Math.toIntExact(itemVo.getQuantity())),userId,userName);
        }


        // 调用微服务计算优惠列表
        InternalReturnObject<List<CouponCalRetVo>> couponCalRetVoListRet = couponService.calculateDiscount(couponCalVoList);
        List<CouponCalRetVo> couponCalRetVoList = couponCalRetVoListRet.getData();
        // 调用微服务计算邮费
        InternalReturnObject<FreightCalculatingRetVo> freightCalRet = freightService.calculateFreight(vo.getRegionId(), freightCalVoList);
        FreightCalculatingRetVo freightCalRetVo = freightCalRet.getData();
        Long express = freightCalRetVo.getFreightPrice();

        Long allPoint = 0L;
        if (vo.getPoint() != null) allPoint = vo.getPoint();


        // 扣积点 如果是预售，则在定金扣除  如果point > 定金 则只扣定金的积点
        if (advanceActRetVo != null) {
            Long advancePrice = advanceActRetVo.getAdvancePayPrice();
            if (allPoint > advancePrice + express) {
                allPoint = advancePrice + express;
            }
        } else {
            if (allPoint > allPrice + express) {
                allPoint = allPrice + express;
            }
        }

        // 使用积点 获得真实使用的积点数
//        InternalReturnObject<PointUseRetVo> pointUseRetVoInternalReturnObject = customerService.usePoint(userId, allPoint);
        CustomerModifyPointsVo customerModifyPointsVo=new CustomerModifyPointsVo();
        //扣积点，负数
        customerModifyPointsVo.setPoints(-allPoint);
        InternalReturnObject<CustomerModifyPointsVo> pointUseRetVoInternalReturnObject = customerService.changeCustomerPoint(userId, customerModifyPointsVo);
        allPoint = -pointUseRetVoInternalReturnObject.getData().getPoints();

        Long resPoints = allPoint > express ? allPoint - express : 0;
        // 计算总共的优惠价格
        Long allDiscount = 0L;
        for (int i = 0; i < orderItemList.size(); i++) {
            for (int j = 0; j < couponCalRetVoList.size(); j++) {
                if (couponCalRetVoList.get(j).getProductId().equals(orderItemList.get(i).getProductId())) {
                    orderItemList.get(i).setDiscountPrice(couponCalRetVoList.get(j).getDiscountPrice());
                    allDiscount += couponCalRetVoList.get(j).getDiscountPrice() * orderItemList.get(i).getQuantity();
                    orderItemList.get(i).setPoint(Math.round(1.0 * resPoints * orderItemList.get(i).getPrice() * orderItemList.get(i).getQuantity() / allPrice));
                    break;
                }
            }
        }

        allDiscount = Math.round(1.0 * allDiscount / 10);

        // 防止优惠券重复使用
        for (Long couponId : couponSet) {
            customerService.useCoupon(userId,userName,couponId);
        }

        // 新建订单orderBO
        Order finalOrder = cloneVo(vo, Order.class);
        finalOrder.init();
        finalOrder.setShopId(orderItemList.get(0).getShopId());
        finalOrder.setCustomerId(userId);
        finalOrder.setDiscountPrice(allDiscount);
        finalOrder.setExpressFee(freightCalRetVo.getFreightPrice());
        finalOrder.setOriginPrice(allPrice);
        finalOrder.setPoint(allPoint);
        finalOrder.setOrderItems(orderItemList);
        setPoCreatedFields(finalOrder, userId, userName);
        if (advanceActRetVo == null) {
            finalOrder.setAdvancesaleId(0L);
        }
        if (grouponActRetVo == null) {
            finalOrder.setGrouponId(0L);
        }

        // 发送order message 由消费者处理存进数据库
        rocketMQService.sendOrderMessage(finalOrder);


        // 如果是预售 返回 定金和尾款两个支付信息
        // 积点算在定金 运费算在尾款
        if (advanceActRetVo != null) {
            NewOrderRetVo retVo1 = new NewOrderRetVo();
            retVo1.setOrderSn(finalOrder.getOrderSn() + "-D");
            retVo1.setBeginTime(LocalDateTime.now().atZone(ZoneId.systemDefault()));
            retVo1.setEndTime(advanceActRetVo.getPayTime().withZoneSameInstant(ZoneId.systemDefault()));
            retVo1.setDescr(finalOrder.getOrderSn() + " - 预售定金");
            retVo1.setDocumentType(DocumentType.ADVANCEPRICE);
            retVo1.setAmount(advanceActRetVo.getAdvancePayPrice() - allPoint);

            NewOrderRetVo retVo2 = new NewOrderRetVo();
            retVo2.setOrderSn(finalOrder.getOrderSn() + "-W");
            retVo2.setBeginTime(advanceActRetVo.getPayTime().withZoneSameInstant(ZoneId.systemDefault()));
            retVo2.setDescr(finalOrder.getOrderSn() + " - 预售尾款");
            retVo2.setDocumentType(DocumentType.RESTPRICE);
            retVo2.setAmount(allPrice - advanceActRetVo.getAdvancePayPrice() + finalOrder.getExpressFee());
            // 发送订单支付确认消息 若到时未支付 则取消订单 释放库存
            rocketMQService.sendOrderCheckMessage(finalOrder.getOrderSn());
            return new ReturnObject<>(Stream.of(retVo1, retVo2).collect(Collectors.toList()));

        }

        // 建立返回的vo
        NewOrderRetVo retVo = new NewOrderRetVo();
        retVo.setOrderSn(finalOrder.getOrderSn());
        retVo.setBeginTime(LocalDateTime.now().atZone(ZoneId.systemDefault()));
        retVo.setEndTime(LocalDateTime.now().plusMinutes(30).atZone(ZoneId.systemDefault()));
        if (grouponActRetVo != null) {
            retVo.setDescr(finalOrder.getOrderSn() + " - 新团购订单");
        } else {
            retVo.setDescr(finalOrder.getOrderSn() + " - 新订单");
        }
        retVo.setDocumentType(DocumentType.ORDER);
        retVo.setAmount(finalOrder.getOriginPrice() - finalOrder.getDiscountPrice() + finalOrder.getExpressFee() - finalOrder.getPoint());

        // 发送定时消息，三十分钟没支付则取消
        rocketMQService.sendOrderCheckMessage(finalOrder.getOrderSn());
        return new ReturnObject<>(Stream.of(retVo).collect(Collectors.toList()));
    }


    private ReturnObject checkProductOnSale(InternalReturnObject<ProductRetVo> productRet, InternalReturnObject<OnSaleRetVo> onSaleRet) {
        if (productRet.getData() == null) return new ReturnObject(RESOURCE_ID_NOTEXIST, "该商品不存在");
        if (productRet.getData().getState() != 2) return new ReturnObject(STATENOTALLOW, "该货品未上架");
        if (onSaleRet.getData() == null) return new ReturnObject(RESOURCE_ID_OUTSCOPE, "该价格销售不存在");
        if (onSaleRet.getData().getState() != ActState.ONLINE.getCode().byteValue())
            return new ReturnObject(STATENOTALLOW, "该商品未上线");
        if (!onSaleRet.getData().getProduct().getId().equals(productRet.getData().getId()))
            return new ReturnObject<>(RESOURCE_ID_OUTSCOPE, "不是该销售的货品");
        return new ReturnObject();
    }

    private ReturnObject internalCancelOrder(Long userId, String userName, Order order) {

        List<Order> subOrders = new ArrayList();
        List<OrderItem> orderItemList = new ArrayList<>();
        if (order.getPid() != 0) {
            ReturnObject ret2 = orderDao.getOrder(order.getPid());
            if (ret2.getData() == null) {
                return ret2;
            }
            order = cloneVo(ret2.getData(), Order.class);
            ReturnObject ret3 = orderDao.getOrderByPid(order.getId());
            List<OrderPo> orderPos = (List<OrderPo>) ret3.getData();
            for (OrderPo orderPo : orderPos) {
                Order subOrder = cloneVo(orderPo, Order.class);
                subOrders.add(subOrder);
            }
        }
        // 已完成不能取消
        if (order.getState().equals(Order.State.COMPLETED.getCode())) {
            return new ReturnObject(RESOURCE_ID_OUTSCOPE, "当前状态禁止此操作");
        }
        // 新订单不退款
        if (order.getState().equals(Order.State.NEW_ORDER.getCode()) || order.getState().equals(Order.State.PENDING_FINAL_PAYMENT.getCode())) {
            order.setState(Order.State.CANCELED.getCode());
            orderDao.updateOrder(order, userId, userName);
            return new ReturnObject<>();
        }


        // 预售退两笔
        if (order.getAdvancesaleId() != null && order.getAdvancesaleId() != 0) {
            InternalReturnObject<AdvanceSaleRetVo> actVoRet = activityService.getAdvanceActById(order.getAdvancesaleId());
            if (actVoRet.getData() != null) {

                AdvanceSaleRetVo act = actVoRet.getData();
                Long restAmount = order.getOriginPrice() - order.getExpressFee();
                String sn = order.getOrderSn();
                paymentService.refundAll(sn + "-D", (byte) 0, "取消订单退定金");
                paymentService.refund(sn + "-W", restAmount, (byte) 0, "取消订单退尾款");

                order.setState(Order.State.WAIT_REFUND.getCode());
                orderDao.updateOrder(order, userId, userName);
                return new ReturnObject<>();
            }
            return new ReturnObject<>(RESOURCE_ID_NOTEXIST, "该预售活动不存在");
        }
        // 普通退全款
        Long finalAmount = order.getOriginPrice() - order.getPoint() - order.getDiscountPrice() + order.getExpressFee();
        String sn = order.getOrderSn();

        paymentService.refund(order.getOrderSn(), finalAmount, (byte) 0, "取消订单退全款");
        order.setState(Order.State.WAIT_REFUND.getCode());
        orderDao.updateOrder(order, userId, userName);
        if (subOrders.size() != 0) {
            for (Order subOrder : subOrders) {
                subOrder.setState(Order.State.WAIT_REFUND.getCode());
                orderDao.updateOrder(subOrder, userId, userName);
            }
        }
        return new ReturnObject<>();
    }

}
